package logger

import (
	"fmt"
	"os"
	"path/filepath"
	"sync"
	"time"

	"game-simple/internal/infrastructure/config"

	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
	"gopkg.in/natefinch/lumberjack.v2"
)

var (
	Logger *zap.Logger
	Sugar  *zap.SugaredLogger
)

func InitLogger() error {
	cfg := config.GetConfig()
	if cfg == nil {
		return fmt.Errorf("config not loaded")
	}

	// 创建日志目录
	logDir := filepath.Dir(cfg.Log.File)
	if err := os.MkdirAll(logDir, 0755); err != nil {
		return fmt.Errorf("failed to create log directory: %w", err)
	}

	// 配置日志级别
	var zapLevel zapcore.Level
	switch cfg.Log.Level {
	case "debug":
		zapLevel = zapcore.DebugLevel
	case "info":
		zapLevel = zapcore.InfoLevel
	case "warn":
		zapLevel = zapcore.WarnLevel
	case "error":
		zapLevel = zapcore.ErrorLevel
	default:
		zapLevel = zapcore.InfoLevel
	}

	// 配置编码器
	encoderConfig := zap.NewProductionEncoderConfig()
	encoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder
	encoderConfig.EncodeLevel = zapcore.CapitalLevelEncoder
	encoderConfig.EncodeCaller = zapcore.ShortCallerEncoder

	// 配置日志轮转（每日分割）
	var writeSyncer zapcore.WriteSyncer
	if cfg.Log.DailyRotation {
		// 使用自定义的每日分割 WriteSyncer
		writeSyncer = newDailyRotationWriter(cfg.Log.File, cfg.Log.MaxSize, cfg.Log.MaxBackups, cfg.Log.MaxAge, cfg.Log.Compress)
	} else {
		// 使用 lumberjack 进行大小分割
		lumberJackLogger := &lumberjack.Logger{
			Filename:   cfg.Log.File,
			MaxSize:    cfg.Log.MaxSize,
			MaxBackups: cfg.Log.MaxBackups,
			MaxAge:     cfg.Log.MaxAge,
			Compress:   cfg.Log.Compress,
		}
		writeSyncer = zapcore.AddSync(lumberJackLogger)
	}

	// 同时输出到文件和控制台
	consoleEncoder := zapcore.NewConsoleEncoder(encoderConfig)
	consoleWriter := zapcore.AddSync(os.Stdout)

	fileEncoder := zapcore.NewJSONEncoder(encoderConfig)
	core := zapcore.NewTee(
		zapcore.NewCore(consoleEncoder, consoleWriter, zapLevel),
		zapcore.NewCore(fileEncoder, writeSyncer, zapLevel),
	)

	// 创建 Logger
	Logger = zap.New(core, zap.AddCaller(), zap.AddStacktrace(zapcore.ErrorLevel))
	Sugar = Logger.Sugar()

	return nil
}

// dailyRotationWriter 实现每日日志分割
type dailyRotationWriter struct {
	filename   string
	maxSize    int
	maxBackups int
	maxAge     int
	compress   bool
	current    *lumberjack.Logger
	lastDate   string
	mu         sync.Mutex
}

func newDailyRotationWriter(filename string, maxSize, maxBackups, maxAge int, compress bool) zapcore.WriteSyncer {
	writer := &dailyRotationWriter{
		filename:   filename,
		maxSize:    maxSize,
		maxBackups: maxBackups,
		maxAge:     maxAge,
		compress:   compress,
		lastDate:   getDateString(),
	}
	writer.current = writer.getFileWriter()
	return writer
}

func (w *dailyRotationWriter) Write(p []byte) (n int, err error) {
	w.mu.Lock()
	defer w.mu.Unlock()

	// 检查是否需要切换到新的日志文件（新的一天）
	currentDate := getDateString()
	if currentDate != w.lastDate {
		// 新的一天，切换到新的日志文件
		w.lastDate = currentDate
		w.current = w.getFileWriter()
	}
	return w.current.Write(p)
}

func (w *dailyRotationWriter) Sync() error {
	// lumberjack 会自动管理文件同步，这里不需要特殊处理
	return nil
}

func (w *dailyRotationWriter) getFileWriter() *lumberjack.Logger {
	// 生成带日期的日志文件名：app.log -> app.2024-01-01.log
	logDir := filepath.Dir(w.filename)
	logBase := filepath.Base(w.filename)
	ext := filepath.Ext(logBase)
	nameWithoutExt := logBase[:len(logBase)-len(ext)]
	dateStr := getDateString()
	dailyFilename := filepath.Join(logDir, fmt.Sprintf("%s.%s%s", nameWithoutExt, dateStr, ext))

	return &lumberjack.Logger{
		Filename:   dailyFilename,
		MaxSize:    w.maxSize,
		MaxBackups: w.maxBackups,
		MaxAge:     w.maxAge,
		Compress:   w.compress,
	}
}

func getDateString() string {
	return time.Now().Format("2006-01-02")
}

// 便捷方法
func Info(msg string, fields ...zap.Field) {
	Logger.Info(msg, fields...)
}

func Error(msg string, fields ...zap.Field) {
	Logger.Error(msg, fields...)
}

func Warn(msg string, fields ...zap.Field) {
	Logger.Warn(msg, fields...)
}

func Debug(msg string, fields ...zap.Field) {
	Logger.Debug(msg, fields...)
}

func Fatal(msg string, fields ...zap.Field) {
	Logger.Fatal(msg, fields...)
}

// Sugared 便捷方法（支持格式化字符串）
func Infof(template string, args ...interface{}) {
	Sugar.Infof(template, args...)
}

func Errorf(template string, args ...interface{}) {
	Sugar.Errorf(template, args...)
}

func Warnf(template string, args ...interface{}) {
	Sugar.Warnf(template, args...)
}

func Debugf(template string, args ...interface{}) {
	Sugar.Debugf(template, args...)
}

func Fatalf(template string, args ...interface{}) {
	Sugar.Fatalf(template, args...)
}
